﻿// 文件名：函数模版
// 创建时间：2021/6/28/星期一 19:32:59

#include <iostream>
using namespace std;
#include <string>

/*
1、函数模版的写法
template<typename T>
	返回值类型 函数名(参数列表)
2、函数模版的重载
	与函数的重载相同
3、函数模版的显式具体化
	3.1具体化格式：

		template <> 返回值类型 函数名<具体化的类型>(参数列表)
		or
		template <> 返回值类型 函数名(参数列表)
	3.2使用显式具体化，不会按照模版来定义，而是用指定的具体化方案来定义
4、显式具体化和显式实例化
	4.1显式实例化
		实例化是按照模版来定义
		一般都是隐式实例化，显式实例化的格式是：
			template 返回值类型 函数名<具体实例化类型>(参数列表)
	4.2显式具体化
		具体化不按照模版来定义
		在template后需要加上<>

5、编译器调用同名函数的优先级
	5.1 常规函数调用优先于模版函数
*/


//函数模版示例1,实现两个数据交换
//声明一个函数模版
template <typename T>
void Swap(T &a, T &b);
void funtemp()
{
	int a = 10;
	int b = 20;
	cout << "交换两个整型数据" << endl;
	cout << "交换前：" << endl;
	cout << "a = " << a << ", b = " << b << endl;
	Swap(a, b);
	cout << "交换后：" << endl;
	cout << "a = " << a << ", b = " << b << endl;

	cout << "交换两个double类型数据" << endl;
	double x = 12.2;
	double y = 23.4;
	cout << "交换前：" << endl;
	cout << "x = " << x << ", y = " << y << endl;
	Swap(x, y);
	cout << "交换后：" << endl;
	cout << "x = " << x << ", y = " << y << endl;
}
template <typename T>
void Swap(T &a, T &b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}


//函数模版示例2，实现两个数组的交换
//函数模版声明+重载
template <typename T>
void Swap(T * a, T * b, int n);//函数模版的参数列表里面不一定都是模版类型
void show(int a[]);
const int SIZE = 5;
void twotemps()
{
	int a[SIZE] = { 1,2,3,4,5 };
	int b[SIZE] = { 5,4,3,2,1 };
	cout << "交换两个整型数组" << endl;
	cout << "交换前：" << endl;
	show(a);
	show(b);
	cout << "交换后：" << endl;
	Swap(a, b, SIZE);
	show(a);
	show(b);
}


template <typename T>
void Swap(T* a,T* b, int n)
{
	T temp;
	for (int i = 0; i < n; i++)
	{
		temp = a[i];
		a[i] = b[i];
		b[i] = temp;
	}
}

void show(int a[])
{
	for (int i = 0; i < SIZE; i++)
	{
		cout << "arr[" << i << "] = " << a[i] << '\t';
	}
	cout << '\n';
}

//函数模版示例3，函数模版的显式具体化
//定义结构体
struct Job
{
	string name;
	double salary;
	int floor;
};
//实现两个结构体交换部分数据
void show(Job job);//重载show函数
template <> void Swap<Job>(Job &job1, Job &job2);
void twoswap()
{
	Job job1 = { "张三",2500.0,10 };
	Job job2 = { "李四",3000.0,11 };
	//交换前的结构体数据
	cout << "交换结构体中的数据" << endl;
	cout << "交换前" << endl;
	show(job1);
	show(job2);
	Swap(job1, job2);
	cout << "交换后：" << endl;
	show(job1);
	show(job2);
}
//显示（explicit specialization）具体化
template <> void Swap<Job>(Job &j1, Job &j2)
{
	double t1;
	t1 = j1.salary;
	j1.salary = j2.salary;
	j2.salary = t1;
	int t2;
	t2 = j1.floor;
	j1.floor = j2.floor;
	j2.floor = t2;
}
void show(Job j)
{
	cout << "姓名：" << j.name << " 工资：" << j.salary << " 楼层：" << j.floor << endl;
}


//函数重载、函数模版、函数模版重载的调用规则
//编译器选择哪个函数版本？？
template<typename T>
void showArray(T arr[], int n); //template A，使用的数组名
template<typename T>
void showArray(T * arr[], int n); //template B，使用的是指针数组
struct debts
{
	char name[50];
	double amount;
};

void temptempover()
{
	int things[6] = { 13,31,131,52,32,12 };
	struct debts mr_E[3] = 
	{
		{"张三",2500.0},
		{"李四",1300.0},
		{"王五",1800.0}
	};
	double * pd[3];//定义指针数组，即三个指针
	for (int i = 0; i < 3; i++)
	{
		pd[i] = &mr_E[i].amount;
	}
	cout << "显示数组中的数据" << endl;
	showArray(things, 6); //使用template A
	showArray(pd, 3);//使用template B
}

template<typename T> //template A
void showArray(T arr[], int n)
{
	cout << "调用template A" << endl;
	for (int i = 0; i < n; i++)
	{
		cout << arr[i] << ' ';
	}
	cout << '\n';
}

template<typename T>
void showArray(T * arr[], int n)
{
	cout << "调用template B" << endl;
	for (int i = 0; i < n; i++)
	{
		cout << *arr[i] << ' ';
	}
	cout << '\n';
}



int main()
{
	//函数模版示例1
	funtemp();
	
	//函数模版示例2
	twotemps();

	//函数模版示例3
	twoswap();

	//函数重载示例4
	temptempover();
	system("pause");
	return 0;
}